home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Practical Algorithms for Image Analysis
/
Practical Algorithms for Image Analysis.iso
/
TARFILE.GZ
/
tarfile
/
ch_4.3
/
xcc
/
cc.c
next >
Wrap
C/C++ Source or Header
|
1999-09-11
|
28KB
|
1,008 lines
/*
* cc.c
*
* Practical Algorithms for Image Analysis
*
* Copyright (c) 1997 1997, 1998, 1999 MLMSoftwareGroup, LLC
*/
/*
* C(enter)C(ircular disks)
*
* functions required in determination of center positions of circular disks
*/
#include "xcc.h"
#define OFF 0
#define ON 1
#define NEW 1 /* flag to indicate init of new dsk */
#define CUR 0
#define LEFT -1
#define RIGHT 1
#define R_COMP 1 /* methods to estimate ctr r-coord */
#define INTERS 2
#define METHOD INTERS
#define MAX_INDEX 255
#define ID_OVLP_LM 0.1 /* cut-off for ``ideal'' circles */
#define AP_OVLP_LM 3.0
#define OVLP_LM AP_OVLP_LM
#define SHIFT_LM OVLP_LM /* cut-off for rel segm pos (``shift'') */
#undef DPRINT
#undef DBG
#undef SHOW_NEW_ADISK
#undef DBG_ENC_ROW
#undef DBG_OVLP
#undef DBG_SYMM_OVLP
#undef DBG_INSP
#undef DBG_EVAL_CTR
/* globals */
extern int del_ir;
extern float ddia;
/*
* initialize new disk structure (the structure itself already exists)
*/
int
init_disk (struct disk *ndsk, int nch)
{
int ich;
if ((ndsk->chords = (struct triple *) calloc (nch + 1, sizeof (struct triple))) == NULL) {
printf ("\n...mem alloc for *ndsk->chords failed!!\n");
return (0);
}
/* initialize structure */
ndsk->nch = 0;
ndsk->ctr.y = ndsk->ctr.x = -1;
ndsk->rad = -1;
ndsk->Status = Active;
ndsk->Type = Accept;
for (ich = 0; ich < nch; ich++) {
ndsk->chords[ich].r = -1;
ndsk->chords[ich].cl = ndsk->chords[ich].cr = -1;
}
return (1);
}
/*
* set current disk to InActive status
*/
int
close_disk (struct disk *cdsk)
{
if ((cdsk->Status == Active)) {
cdsk->Status = InActive;
return (1);
}
else {
printf ("\nCLOSE_DISK: cur disk not Active\n");
return (0);
}
}
/*
* set current disk to Reject type
*/
int
flag_disk (struct disk *cdsk)
{
if ((cdsk->Type == Accept)) {
cdsk->Type = Reject;
return (1);
}
else {
printf ("\nFLAG_DISK: cur disk type not Accept\n");
return (0);
}
}
/*
* fetch set of coefficients for 1d edge detector
*/
void
fetch_edge_det (float *ef, int nf)
{
}
/*
* apply edge detection filter to input array, y, via cyclic (1d)
* convolution; return result in input array;
*/
void
edge_det (unsigned char *y, int n, float *f, int nf)
{
double *yy;
/*
* to be implemented
*/
if ((yy = (double *) calloc (n, sizeof (double))) == NULL) {
printf ("\n...mem alloc for array yy of type double failed");
exit (1);
}
free (yy);
}
/*
* given symmetric overlap between the current edge tuple and the last
* chord in the array of chords associated with the Active disk currently
* under inspection, determine whether to add cetpl to cdsk:
* given cetpl and disk_dia, compute center positions for the two circles
* of which cetpl may form a chord (one center position lying above, the
* other below the current row); compare the estimate(s) so derived with
* those computed in the same way for cdsk_ldchrd (in the case that
* cdsk only contains that one chord) or with the center coordinates
* currently stored in cdsk; test the separation between row-coordinates
* (the column coordinate passes trivially, given the condition of symmetric
* overlap !!), to make a decision about acceptance of cetpl into cdsk;
*
* in comparing row coordinates of potential center positions, take
* advantage of simple geometrical facts, given that cetpl follows
* cdsk_lchrd in the raster scan; thus if (cre-cle) >= (crc-clc), cetpl and
* cdsk_lchrd can only be part of the same circle if that circle's center
* r-coordinate exceeds rc; hence, only ruc need be inspected; the analogous
* conclusion holds if (cre-cle) <= (crc-clc): cetpl and cdsk_lchrd can
* only be part of the same circle if the center r-coordinate is smaller
* than re; hence, only rle need be inspected;
*/
Boolean
insp_Adsk (int ir, struct edge_tuple *cetpl, struct disk *cdsk)
{
struct triple *cdsk_lchrd;
double rue, rle;
double rc, ruc, rlc;
double del_ce, del_cc;
double dcr, ec_r;
double min_r_dist;
Boolean AccRejStat;
/* initialize variables */
cdsk_lchrd = &cdsk->chords[(cdsk->nch) - 1];
del_ce = (double) (cetpl->cr - cetpl->cl);
del_cc = (double) (cdsk_lchrd->cr - cdsk_lchrd->cl);
#ifdef DBG_INSP
printf ("INSP_ADSK -- estimate ctr r-coord: METHOD %d\n", METHOD);
#endif
/*
* estimate coordinates of circle center, based on those already stored in
* cdsk and the vertex coords of cetpl; the column coord is trivially found
* based on symmetry, the r-coord requires more effort;
*
* two methods are employed, depending on whether cdsk contains
* only a single chord or several (more than one) chord
*
* Method 1:
* ---------
* compare the four possible center r-coords, a pair each derived from
* the disk chord and from cetpl, relying on the initial estimate, disk_dia
* of the disk size; this is robust only in the absence of contour noise
* Method 2:
* ---------
* construct the normal to each of the line segments {(re, cle), (rc, clc)}
* and {(re, cre), (rc, crc)} and find the r-coords of their intersection
* point(s) with the line d(isk)c(center)c == 0.5(clc+crc)=const (which
* contains the disk center); given dcc, the desired r-coords are readily
* found by evaluating pertinent slopes;
*/
switch (METHOD) {
case 1:
rue = (double) ir + 0.5 * sqrt (SQR (ddia) - SQR (del_ce));
rle = (double) ir - 0.5 * sqrt (SQR (ddia) - SQR (del_ce));
if (cdsk->nch == 1) {
rc = (double) cdsk->chords[(cdsk->nch) - 1].r;
ruc = rc + 0.5 * sqrt (SQR (ddia) - SQR (del_cc));
rlc = rc - 0.5 * sqrt (SQR (ddia) - SQR (del_cc));
if ((del_ce - del_cc) >= SHIFT_LM) { /* etpl > chord */
if (MIN (fabs (rue - ruc), fabs (rle - ruc)) < del_ir)
AccRejStat = Pass;
else
AccRejStat = Fail;
}
if ((del_cc - del_ce) >= SHIFT_LM) { /* chord > etpl */
if ((min_r_dist = MIN (fabs (ruc - rle), fabs (rlc - rle))) < del_ir)
AccRejStat = Pass;
else
AccRejStat = Fail;
}
}
else {
dcr = (double) cdsk->ctr.y;
if ((min_r_dist = MIN (fabs (rue - dcr), fabs (rle - dcr))) < del_ir)
AccRejStat = Pass;
else
AccRejStat = Fail;
}
#ifdef DBG_INSP
if (cdsk->nch == 1) {
printf (" ctr r-coord derived from chrd, ddia:\n");
printf (" ruc=%lf, rlc=%lf\n", ruc, rlc);
}
else {
printf (" ctr r-coord derived from etpl, ddia:\n");
printf (" rue=%lf, rle=%lf\n", rue, rle);
}
printf ("-->min r-dist to estim center: %lf\n", min_r_dist);
#endif
break;
case 2:
ec_r = pbi_ctr (ir, cetpl, cdsk_lchrd); /* est ctr r-coord */
if (cdsk->nch == 1) {
rc = (double) cdsk->chords[(cdsk->nch) - 1].r;
ruc = rc + 0.5 * sqrt (SQR (ddia) - SQR (del_cc));
rlc = rc - 0.5 * sqrt (SQR (ddia) - SQR (del_cc));
if ((min_r_dist = MIN (fabs (ruc - ec_r), fabs (rlc - ec_r))) < del_ir)
AccRejStat = Pass;
else
AccRejStat = Fail;
}
else {
dcr = (double) cdsk->ctr.y;
if ((min_r_dist = fabs (dcr - ec_r)) < del_ir)
AccRejStat = Pass;
else
AccRejStat = Fail;
}
#ifdef DBG_INSP
if (cdsk->nch == 1) {
printf (" ctr r-coord derived from chrd, ddia:\n");
printf (" ruc=%lf, rlc=%lf\n", ruc, rlc);
}
else {
printf (" cdsk cur ctr r-coord: dcr=%lf,\n", dcr);
}
printf (" ctr r-coord from inters of perp bis: ");
printf (" ec_r=%lf\n", ec_r);
printf ("-->min r-dist to estim center: %lf\n", min_r_dist);
#endif
break;
}
return (AccRejStat);
}
/*
* find latest entry in chord array of current disk
*/
int
find_cdsk_lchrd (int ir, struct disk *cdsk)
{
int chrd_row;
if (cdsk->nch == 0) {
printf (" current disk structure empty\n");
return (-1);
}
else if (((chrd_row = cdsk->chords[cdsk->nch - 1].r) != ir - del_ir) &&
(chrd_row != ir)) {
#ifdef DPRINT
printf ("FIND_CDSK_LCHRD -- WARNING: ");
printf ("--> row %3d out of order -- disk chord index: %3d\n",
chrd_row, cdsk->nch - 1);
#endif
return (-1);
}
else {
return (cdsk->nch - 1); /* return index of last filled chrd */
}
}
/*
* find all Active disks currently listed in dll:
*
* proceeding from list tail, reset dll list pointer to the position of
* the ``oldest'' remaining Active disk which, by construction, is the
* disk most distant from the tail of the list; an efficient way to
* find the desired position entails ''rewinding'' the current list pointer
* until either
* -->the first InActive disk is encountered:
* set AdskStatus to Fail, advance list pointer to point to Active disk
*
* or
* -->the head of dll is reached (without encountering any InActive disk):
* AdskStatus remains True, list pointer points to Active disk
*/
struct linktype *
find_all_Adsks (struct linklist *dll)
{
struct disk *cdsk;
int nad, ndll;
Boolean DllStatus;
Boolean AdskStatus;
lltail (dll);
if ((ndll = ll_length (dll)) == 0)
return (dll->clp);
#ifdef DPRINT
printf ("\nFIND_ALL_ADSKS -- rewind dll\n");
#endif
nad = 0;
DllStatus = AdskStatus = True;
do {
if ((cdsk = (struct disk *) dll->clp->item)->Status == Active) {
#ifdef DPRINT
printf (" %d ", ++nad);
#endif
DllStatus = llprevious (dll);
}
else
AdskStatus = False;
} while ((DllStatus == True) && (AdskStatus == True));
if (AdskStatus == False)
llnext (dll);
#ifdef DPRINT
printf ("\n...rewinding dll (AdskStatus: %d)", AdskStatus);
printf (" -->identified %d Active disks\n", nad);
#endif
return (dll->clp);
}
/*
* find next disk in dll with Active status
*/
struct linktype *
find_next_Adsk (struct linklist *dll)
{
struct disk *cdsk;
while (llnext (dll) == True) {
if ((cdsk = (struct disk *) dll->clp->item)->Status == Active)
return (dll->clp);
}
return ((struct linktype *) NULL);
}
/*
* add new disk structure to tail of dll, reset list pointer to original pos
*/
void
app_ndsk_to_dll (char *ndsk, struct linklist *dll)
{
struct linktype *adlp;
adlp = dll->clp;
lltail (dll);
lladd ((char *) ndsk, dll);
dll->clp = adlp;
}
/*
* insert new disk structure into dll so as to retain the list of Active
* disks in the order of increasing etpl column coordinates; reset list
* pointer to original pos
*/
void
ins_ndsk_to_dll (char *ndsk, struct linklist *dll, int shift)
{
struct linktype *adlp;
adlp = dll->clp;
if (shift == LEFT)
lladdprev ((char *) ndsk, dll);
if (shift == RIGHT)
lladd ((char *) ndsk, dll);
dll->clp = adlp;
}
/*
* add new chord, converted from edge tuple, to disks's array of chords;
* the disk may be a currently Active disk already containing chords or
* a newly initialized disk
*/
Boolean
chord_to_Adsk (int ir, int nch, struct edge_tuple *cetpl, struct disk *cdsk, int disk_type, int ncch)
{
struct triple *cdsk_lchrd;
int memalloc;
int cl, cr;
int cctr_r, nctr_r;
if (disk_type == NEW) { /* init new disk */
if ((memalloc = init_disk (cdsk, nch)) == 0) {
#ifdef DPRINT
printf ("\nCHORD_TO_DISK -- disk init failed\n");
#endif
return (Fail);
}
}
else { /* posit chord array ptr of cur dsk */
if (cdsk->Status != Active) {
printf ("\nCHORD_TO_ADISK -- cur disk must be Active\n");
return (Fail);
}
}
/* store etpl in cdsk */
cdsk->chords[ncch].r = ir;
cdsk->chords[ncch].cl = cetpl->cl;
cdsk->chords[ncch].cr = cetpl->cr;
cdsk->nch++;
/*
* update circle center pos and radius
*/
if (cdsk->nch == 1) { /* first estim of cntr pos and rad */
cl = cdsk->chords[cdsk->nch - 1].cl;
cr = cdsk->chords[cdsk->nch - 1].cr;
cdsk->ctr.y = (short) (ir + 0.5 * sqrt (SQR (ddia) - SQR (cr - cl)));
cdsk->ctr.x = (cetpl->cl + cetpl->cr) / 2;
cdsk->rad = F_TO_INT (0.5 * ddia);
}
else {
cdsk_lchrd = &cdsk->chords[(cdsk->nch) - 2];
nctr_r = F_TO_INT (pbi_ctr (ir, cetpl, cdsk_lchrd));
if (cdsk->nch == 2)
cdsk->ctr.y = nctr_r;
else {
cctr_r = cdsk->ctr.y;
#ifdef DPRINT
printf ("\n...cctr_r: %d, nctr_r: %d\n", cctr_r, nctr_r);
#endif
cdsk->ctr.y = ((cdsk->nch - 1) * cctr_r + nctr_r) / cdsk->nch;
}
cdsk->rad = eval_rad (cdsk);
#ifdef DPRINT
printf ("\n...ctr y_coord just stored in cdsk: %3d\n", cdsk->ctr.y);
printf ("...estimated radius: %d\n", cdsk->rad);
#endif
}
#ifdef SHOW_NEW_ADISK
printf ("\nCHORD_TO_ADISK: ");
if (disk_type == NEW)
printf ("initialize new Active disk\n");
else
printf ("update existing Active disk\n");
printf (" nof chords in curr Active disk: %d\n", cdsk->nch);
printf (" last (%d-th) chord: [%3d; %3d %3d]\n", ncch,
cdsk->chords[cdsk->nch - 1].r,
cdsk->chords[cdsk->nch - 1].cl,
cdsk->chords[cdsk->nch - 1].cr);
#endif
return (Pass);
}
/*
* determine relative displacement (along rows) of segments with partial
* or vanishing overlap (see find_segm_ovlp())
*
* LEFT/RIGHT: etpl left/right-shifted w/r chord
*/
int
find_segm_shift (struct triple *chrd, struct edge_tuple *cetpl)
{
if (chrd->cl >= cetpl->cr)
return (LEFT);
if (cetpl->cl >= chrd->cr)
return (RIGHT);
}
/*
* given two segments, one disk chord, one edge tuple on successive
* scan lines, establish their mode of overlap: the ovlp flag serves
* to distinguish three cases:
*
* -- ovlp = 0: if no overlap exists, the disk containing the current chord
* is set Inactive; however, a new disk to hold the current edge
* tuple is not yet called for: the edge tuple may still belong
* to another Active disk which would, however, have to lie
* between the current chord and the edge tuple;
*
* -- ovlp =-1: finite partial overlap obtains, so that
*
* yO_et < yO_dc < yF_et < yF_dc,
* or
* yO_dc < yO_et < yF_dc < yF_et;
*
* in either case, a new disk must be inserted into dll to
* hold the current edge tuple as a chord; the disk containing
* the current disk chord is closed (given Inactive status);
* finite overlap obtains if the following two inequalities hold:
*
* yO_et < yF_dc and yO_dc < yF_et,
*
* or vice versa; otherwise, there is no overlap: -->case 0;
* complete overlap is ensured if, in addition to the previous
* inequality, yF_dc < yF_et, or vice versa
*
* -- ovlp = 1: only if one segment symmetrically encloses the other, that is,
* if, given complete overlap, one has in addition,
*
* abs( yO_dc - yO_et ) = abs( yF_et - yF_dc )
*
* or, alternatively,
*
* (yO_dc + yF_dc)/2 = (yO_et + yF_et)/2
*
* does the edge_tuple qualify for further consideration as an
* additional disk chord;
*/
int
find_segm_ovlp (struct triple *chrd, struct edge_tuple *cetpl)
{
int ovlp = 77;
int yOe, yFe, yOc, yFc;
yOc = (int) chrd->cl;
yFc = (int) chrd->cr;
yOe = (int) cetpl->cl;
yFe = (int) cetpl->cr;
#ifdef DBG_OVLP
printf ("FIND_SEGM_OVLP: ");
#endif
if ((yOe < yFc) && (yOc < yFe)) { /* partial ovlp */
if ((yOe <= yOc) && (yFc <= yFe)) { /* etpl encl chrd */
if (fabs ((yOc + yFc) - (yOe + yFe)) < OVLP_LM)
ovlp = 1;
}
else if ((yOc <= yOe) && (yFe <= yFc)) { /* chrd encl etpl */
if (fabs ((yOc + yFc) - (yOe + yFe)) < OVLP_LM)
ovlp = 1;
}
else
ovlp = -1; /* finite partial ovlp */
}
else /* no ovlp */
ovlp = 0;
#ifdef DBG_OVLP
printf (" %d\n", ovlp);
#endif
return (ovlp);
}
/*
* process current edge tuple list, generated in last row scan,
* by assigning edge tuples to disk structures, either to currently
* Active (Incomplete) or to new disks, to be added to disk list;
* Active disks to which no new edge tuple is assigned are given
* Inactive (Complete) status
*/
int
update_disk_list (int ir, int nch, struct linklist *dll, struct linklist *etll)
{
struct linktype *adlp; /* ptr to first Act disk in dll */
struct linktype *sadlp; /* ptr to save init val of adlp */
struct linktype *stdlp; /* ptr to save init val of dll->tail */
struct disk *cdsk; /* pointer to disk at cur dll posit */
struct disk new_disk, *ndsk = &new_disk;
struct edge_tuple *cetpl;
int nnad; /* nof Act disks added to dll */
int ncd; /* nof Act disks closed in cur pass */
int nfd; /* nof Act disks set to type Reject */
int etll_to_dll = OFF;
int ovlp;
//int shift; /* used with ins_ndsk_to_dll() */
int ncch; /* ind of last filled chrd in cdsk */
Boolean AccRejStat; /* test status (Pass/Fail) of etpl */
/*
* scan (col-ordered) edge_tuple list, etll, and update the array of chords
* associated with each disk: this may require inserting new disk structures
* into dll, as well as updating disk structures already present in the list
*
* the emerging list contains disk structures in the order of their
* acquiring Active (Open) status: a new disk, with Active status, is
* added to dll, whenever an edge tuple on the current scan line does not
* satisfy the overlap conditions which would identify it as a chord of one
* of the already Active disks; the edge tuple under consideration is entered
* as a chord of a new disk structure which is in turn inserted into dll;
* any disk which is not intersected by the current scan line (and thus
* acquires no new chord) is given InActive status;
*
* two modes of insertion with different advantages may be considered:
* -- insert new disk at at the end (tail) of dll --> app_ndsk_to_dll();
* dll is doubly sorted: primary key is the row-coord of its first chord,
* secondary key is the col-coord of chords on the same row; this has the
* advantage of maintaining Active disks in a contiguous sequence at the
* end of dll and thus makes it easy to locate all Active disks
* -- insert new disk in according to results of comparing ovlp and shift
* (--> find_segm_shift()) of cdsk_lchrd and etpl --> ins_ndsk_to_dll();
* dll is sorted according to the col-coord of its first chord; this has
* the advantage of requiring only local operations of ovlp and segm
* evaluations when examining a new etpl: only the c-adjacent disks need
* be inspected; however, it has the disadvantage of fragmenting the
* Active portion of dll
* -->possible room for speed-ups at a later stage of development
*/
#ifdef DPRINT
printf ("\n\nUPDATE_DISKLIST -- process new etll\n");
#endif
if (ll_length (etll) == 0) {
#ifdef DPRINT
printf ("\nUPDATE_DISK_LIST -- edge_tuple list empty\n");
printf (" -->no update of disk list required\n");
#endif
return (0);
}
/*
* etll not empty: update disk list; find all Incomplete (Active) disks
* by resetting dll to last Active disk, i.e. the Active disk farthest
* from the tail of dll
*/
sadlp = dll->head;
stdlp = dll->tail;
if ((adlp = find_all_Adsks (dll)) == stdlp) {
if (ll_length (dll) == 0) {
#ifdef DPRINT
printf ("\n...currently no Active disks in dll\n");
printf (" -->cp all chords in etll into Act disk in dll\n");
#endif
etll_to_dll = ON; /* copy etll to dll */
}
}
llhead (etll);
cetpl = (struct edge_tuple *) etll->clp->item;
sadlp = adlp;
nnad = 0;
do { /* scan etll */
/* process segm with matched status */
#ifdef DPRINT
printf ("\nUPDATE_DISK_LIST -- process new etpl\n");
#endif
cetpl = (struct edge_tuple *) etll->clp->item;
if (cetpl->status != Matched)
return (0);
if (etll_to_dll == ON) { /* enter cur etpl into dll */
AccRejStat = chord_to_Adsk (ir, nch, cetpl, ndsk, NEW, 0);
app_ndsk_to_dll ((char *) ndsk, dll);
nnad++;
}
/*
* advance dll->clp by one to point to first Active disk in dll
* (note: mem alloc for an Active disk has already been performed, see above!)
*
* determine ovlp between etpl and disk chord (see function find_segm_ovlp());
* also examine the relative positioning of etpl and chrd: this serves to
* insert new disks into dll in increasing order of segment column coords
*
* etpl l-shifted w/r chrd, i.e. etpl precedes chrd:
* open new disk struct preceding cdsk to hold current tuple
* maintain cdsk Active
* etpl r-shifted w/r chrd, i.e., chrd precedes etpl:
* set cdsk InActive
* retain current etpl and check ovlp with next Adsk in dll
*/
else { /* check overlap betw cur etpl, dsk chords */
dll->clp = sadlp;
AccRejStat = Fail;
do { /* scan Adsks in dll */
adlp = dll->clp;
cdsk = (struct disk *) adlp->item;
if ((ncch = find_cdsk_lchrd (ir, cdsk)) == -1) {
#ifdef DPRINT
printf ("\nUPDATE_DISK_LIST -- ");
printf (" WARNING: row coords of last disk chord incorrect\n");
printf (" ir: %3d, del_ir: %3d\n", ir, del_ir);
/* PROC ERR: halt execution!! */
#endif
}
ovlp = find_segm_ovlp (&(cdsk->chords[cdsk->nch - 1]), cetpl);
if (ovlp == 1) { /* symmetric */
if ((AccRejStat = insp_Adsk (ir, cetpl, cdsk)) == Pass) {
chord_to_Adsk (ir, nch, cetpl, cdsk, CUR, ncch + 1);
}
else {
/* PROC ERR */
AccRejStat = chord_to_Adsk (ir, nch, cetpl, ndsk, NEW, 0);
app_ndsk_to_dll ((char *) ndsk, dll);
nnad++;
}
}
} while ((AccRejStat == Fail) && (llnext (dll) == True));
/* reached tail of dll without inserting etpl */
if (AccRejStat == Fail) {
#ifdef DPRINT
printf ("\nUPDATE_DISK_LIST -- ");
printf (" append new disk to dll\n");
#endif
AccRejStat = chord_to_Adsk (ir, nch, cetpl, ndsk, NEW, 0);
app_ndsk_to_dll ((char *) ndsk, dll);
nnad++;
}
}
} while (llnext (etll) == True);
/*
* etll exhausted: inspect all Active disks which were present in dll prior
* to processing the current etll, that is those between positions pointed
* to by sadlp and stdlp; disks which were not updated in the current pass
* (by receiving an etll segment as a new chord) must be closed
*/
#ifdef DPRINT
printf ("\nUPDATE_DISK_LIST -- etll (row %3d) exhausted\n", ir);
#endif
dll->clp = sadlp;
ncd = nfd = 0;
if (etll_to_dll == ON)
return (nnad);
do {
if ((cdsk = (struct disk *) dll->clp->item)->Status == Active) {
if (cdsk->nch == nch) { /* max nof chords attained */
ncd += close_disk (cdsk);
}
else {
if ((ncch = find_cdsk_lchrd (ir + del_ir, cdsk)) == -1) {
ncd += close_disk (cdsk);
/*
* additional Type-checking may be performed here to Reject disks
*
* example:
* -- segments of disks clipped by left or right edges all have identical
* cl or cr coordinates which may be used to discriminate
*/
/*
* note: counting segments is not a robust criterion to identify clipped
* disks in the presence of size variations
*
* if( cdsk->nch < nch-1 )
* nfd += flag_disk(cdsk);
*/
}
}
}
} while (llnext (dll) == True);
#ifdef DPRINT
printf ("...closed %d disk(s), flagged %d disks\n", ncd, nfd);
#endif
return (nnad);
}
/*
* determine and set status (Matched/UnMatched) currently last entry
* in edge tuple list
*/
Boolean
ReptSegmStatus (struct edge_tuple * letpl, int pix)
{
Boolean Segm_Status;
Segm_Status = letpl->status;
switch (pix) {
case OFF: /* OFF->ON: last tuple Matched? */
if (Segm_Status == UnMatched) {
#ifdef DPRINT
printf ("\n...OFF->ON: last entry in etll UnMatched:");
if (letpl->cr == -1)
printf ("...cr invalid\n");
else
printf ("...unknown origin\n");
#endif
}
else if (Segm_Status == Matched) { /* OK */
}
else {
Segm_Status = UnKnown;
#ifdef DPRINT
printf ("\n...OFF->ON: segm status UnKnown\n");
#endif
}
break;
case ON: /* ON->OFF: last tuple UnMatched */
if (Segm_Status == Matched) {
#ifdef DPRINT
printf ("\n...ON->OFF: last entry in etll already Matched: cr = %3d\n",
(int) letpl->cr);
#endif
}
else if (Segm_Status == UnMatched) { /* OK */
}
else {
Segm_Status = UnKnown;
#ifdef DPRINT
printf ("\n...ON->OFF: segm status UnKnown\n");
#endif
}
break;
}
return (Segm_Status);
}
/*
* given a row extracted from the original image (GRAY_LEV = BNRY), or
* an extracted row which has been subjected to 1d edge detection,
* locate edge points and place successive edge points into tuples
* (cl: OFF->ON transition, cr: ON->OFF transition); each such edge tuple
* gives the y-coordinates delimiting ON-segments (``runs''); the status
* of a segment is Matched if the pair {cl, cr} marks successive OFF->ON,
* ON->OFF transitions in image intensity; otherwise, the segment status is
* UnMatched; edge tuples are entered into a y-ordered edge tuple list;
*/
int
encode_row (unsigned char *row, int nc, struct linklist *etll, int gray_lev)
{
int jc;
int pix;
struct edge_tuple cur_etpl, *cetpl = &cur_etpl;
Boolean Etpl_Status;
if (gray_lev == 0) { /* binary input row */
lltail (etll);
Etpl_Status = Matched;
cetpl->cl = cetpl->cr = -1;
cetpl->status = UnMatched;
pix = OFF;
jc = 0;
while (jc < nc) {
if (*(row + jc) / MAX_INDEX == pix)
jc++;
else {
switch (pix) {
case OFF: /* handle OFF->ON transition */
/* initialize new ON-segm */
cetpl->cl = jc + 1;
cetpl->cr = -1;
cetpl->status = UnMatched;
#ifdef DPRINT
printf ("...jc=%3d: edge tup [%3d %3d] init",
jc, cetpl->cl, cetpl->cr);
#endif
/* enter new tuple into edge_tuple_list */
lltail (etll);
/* status of last ON-segm Matched? */
if (ll_length (etll) > 0) {
Etpl_Status = ReptSegmStatus ((struct edge_tuple *) etll->clp->item, pix);
#ifdef DPRINT
if (Etpl_Status != Matched)
printf ("\nWARNING: prev ON-segm not Matched\n");
#endif
}
lladd ((char *) cetpl, etll);
#ifdef DPRINT
printf ("...entered into etll");
printf (" -->cur list len: %d\n", ll_length (etll));
#endif
pix = ON;
break;
case ON: /* handle ON->OFF transition */
/* complete current ON-segm */
lltail (etll);
/* status of last ON-segm UnMatched? */
if (ll_length (etll) > 0) {
Etpl_Status = ReptSegmStatus ((struct edge_tuple *) etll->clp->item, pix);
if (Etpl_Status != UnMatched)
printf ("\nWARNING: prev ON-segm not UnMatched\n");
}
((struct edge_tuple *) etll->clp->item)->cr = jc;
((struct edge_tuple *) etll->clp->item)->status = Matched;
#ifdef DPRINT
printf ("...jc=%3d: edge tup [%3d %3d] compl", jc, ((struct edge_tuple *) etll->clp->item)->cl,
((struct edge_tuple *) etll->clp->item)->cr);
printf (" -->cur list len: %d\n", ll_length (etll));
#endif
pix = OFF;
break;
}
}
}
}
else if (gray_lev == 1) {
printf ("\n...1d edge detection: to be implemented\n");
}
#ifdef DBG_ENC_ROW
printf ("\nCC.C: display current edge tuple list\n");
show_etpl_list (etll);
#endif
return (etll->listlength);
}